// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.Diagnostics;
using System.IO;

namespace Microsoft.TeamFoundation.Migration.Toolkit
{
    /// <summary>
    /// The configuration class that defines the add-in (provider) definition.  
    /// 
    /// &lt;Provider id="SampleProvider"&gt;
    ///     &lt;AssemblyQualifiedName&gt;FC1_Loader.SampleProviderFactory, FC1_Loader, Version=1.0.0.0, Culture=neutral&lt;/AssemblyQualifiedName&gt;
    /// &lt;/Provider&gt;
    /// </summary>
    [XmlType("Provider")]
    public class MigrationProvider
    {
        /// <summary>
        /// The string ID of the provider.
        /// </summary>
        [XmlAttribute("id")]
        public virtual string Id
        {
            get
            {
                return m_id;
            }
            set
            {
                m_id = value;
            }
        }

        /// <summary>
        /// The assemlby qualified name of the add-in factory type.
        /// </summary>
        public virtual string AssemblyQualifiedName
        {
            get
            {
                return m_assemblyQualifiedName;
            }
            set
            {
                Debug.Assert(m_providerType == null,
                    "Assembly qualified name should be set only once (during de-serialization)");
                Debug.Assert(!string.IsNullOrEmpty(value), "Empty/null qualified name!");
                m_assemblyQualifiedName = value;
            }
        }

        /// <summary>
        /// Returns the instantiated System.Type of the provider factory.
        /// </summary>
        public virtual Type ProviderType
        {
            get
            {
                if (m_providerType == null)
                {
                    lock (m_typeLock)
                    {
                        if (m_providerType == null)
                        {
                            // Load the type
                            if (string.IsNullOrEmpty(AssemblyQualifiedName))
                            {
                                throw new InitializationException(
                                    MigrationToolkitResources.AssemblyQualNameInvalid);
                            }

                            Exception loadException = null;
                            try
                            {
                                m_providerType = System.Type.GetType(AssemblyQualifiedName, false, true);
                            }
                            catch (FileLoadException e)
                            {
                                loadException = e;
                            }
                            if (m_providerType == null)
                            {
                                throw new InitializationException(
                                    string.Format(MigrationToolkitResources.Culture, MigrationToolkitResources.UnableToLoadType, AssemblyQualifiedName));
                            }
                        }
                    }
                }
                return m_providerType;
            }
        }

        internal IConfigFactory CreateFactoryInstance()
        {
            if (ProviderType == null)
            {
                throw new InitializationException(
                    string.Format(MigrationToolkitResources.Culture, MigrationToolkitResources.UnableToLoadType, m_assemblyQualifiedName));
            }

            return (IConfigFactory)Activator.CreateInstance(ProviderType);
        }

        /// <summary>
        /// Creates an instance of the provider factory and invokes the IConfigFactory.CreateInstance method
        /// passing in the provided xmlFragment parameter as the initialization parameter.
        /// </summary>
        /// <param name="xmlFragment">The initialization parameter for the IConfigFactory.CreateInstance method</param>
        /// <returns>An instance of the provider object.</returns>
        public object CreateInstance(Type providerType, string xmlFragment)
        {
            try
            {
                IConfigFactory factory = CreateFactoryInstance();
                return factory.CreateInstance(providerType, xmlFragment);
            }
            catch (Exception e)
            {
                throw new InitializationException(MigrationToolkitResources.ErrorCreatingProviderFromXml, e);
            }
        }

        string m_id;
        string m_assemblyQualifiedName;
        Type m_providerType;
        object m_typeLock = new object();                   // Synchronization object for the type
    }

}
